package com.qumitech.visualnovel.service.novel;

import java.util.*;
import java.io.*;

import com.qumitech.visualnovel.pubdef.constant.BookPublishStateEnum;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONArray;

import com.qumitech.visualnovel.component.thirdapi.aliyun.AliYunOSSUtil;
import com.qumitech.visualnovel.component.util.EncodeUtil;
import com.qumitech.visualnovel.component.config.Config;
import com.qumitech.visualnovel.model.common.BaseResponse;
import com.qumitech.visualnovel.service.account.UserInfoService;
import com.qumitech.visualnovel.datasource.editor.BookDAOMapper;
import com.qumitech.visualnovel.datasource.editor.ChapterDAOMapper;
import com.qumitech.visualnovel.datasource.editor.ReviewRecordDAOMapper;
import com.qumitech.visualnovel.model.dto.ReviewQueryDTO;
import com.qumitech.visualnovel.model.dto.PublishResultDTO;
import com.qumitech.visualnovel.model.dao.console.UserInfo;
import com.qumitech.visualnovel.model.dao.editor.BookDAO;
import com.qumitech.visualnovel.model.dao.editor.ChapterDAO;
import com.qumitech.visualnovel.model.dao.editor.ReviewRecordDAO;
import org.thymeleaf.util.StringUtils;

@Slf4j
@Service
public class ReviewServiceImpl implements ReviewService {
    static final String DATA_PATH = Config.getProperty("app.dataPath");
    static final String SCRIPT_RUNNER = Config.getProperty("app.scriptRunner");

    @Autowired
    UserInfoService userInfoService;

    @Autowired
    BookDAOMapper bookDAOMapper;

    @Autowired
    ChapterDAOMapper chapterDAOMapper;

    @Autowired
    ReviewRecordDAOMapper reviewRecordDAOMapper;

    private List<ChapterDAO> getChapterList(Long bookId, String chapterIndexList) {
        List<ChapterDAO> result = new ArrayList<>();
        JSONArray chapterList = JSONArray.parseArray(chapterIndexList);
        for (int idx = 0; idx < chapterList.size(); ++idx) {
            ChapterDAO chapter = chapterDAOMapper.getChapter(bookId, chapterList.getInteger(idx));
            if (chapter != null) result.add(chapter);
        }
        return result;
    }

    @Override
    public void publishTask() {
        Map<Long, Set<Integer>> taskMap = new HashMap<>();
        List<ChapterDAO> updateList = chapterDAOMapper.getPublishTask();
        updateList.forEach(item -> {
            Long bookId = item.getBookId();
            Integer chapterIndex = item.getIndex();
            if (!taskMap.containsKey(bookId)) {
                taskMap.put(bookId, new HashSet<Integer>());
            }
            taskMap.get(bookId).add(chapterIndex);
        });

        for (Long bookId : taskMap.keySet()) {
            String strBookId = String.valueOf(bookId);
            String strIndexList = JSON.toJSONString(taskMap.get(bookId));
            log.info("publish visual book task: bookId={}, indexList={}", strBookId, strIndexList);

            try {
                List<String> commands = new ArrayList<>(Arrays.asList("bash", SCRIPT_RUNNER, "publish", strBookId, strIndexList));
                Process process = new ProcessBuilder(commands).redirectErrorStream(true).start();
            } catch (IOException e) {
                log.error("failed to execute publish", e);
            }

            //一次只发布一本书
            return;
        }
    }

    @Override
    public BaseResponse reviewList(ReviewQueryDTO param) {
        int total = reviewRecordDAOMapper.total(param);
        List<ReviewRecordDAO> list = reviewRecordDAOMapper.list(param);

        BaseResponse result = new BaseResponse(new JSONArray(), total);
        for (ReviewRecordDAO item : list) {
            BookDAO book = bookDAOMapper.selectByPrimaryKey(item.getBookId());
            JSONObject jItem = new JSONObject();
            jItem.put("id", item.getId());
            jItem.put("bookId", item.getBookId());
            jItem.put("message", item.getMessage());
            jItem.put("attachments", item.getAttachments());
            jItem.put("reviewState", item.getReviewState());
            jItem.put("submitNum", item.getSubmitNum());
            jItem.put("releasedNum", item.getPublishedNum());
            jItem.put("applicant", item.getApplicant());
            jItem.put("reviewer", item.getReviewer());
            jItem.put("submitAt", item.getCreatedAt());
            jItem.put("reviewAt", item.getReviewAt());
            jItem.put("chapterIndexList", item.getChapterIndexList());
            jItem.put("author", bookDAOMapper.getAuthorName(book.getId()));
            jItem.put("title", book.getTitle());
            jItem.put("publishState", book.getPublishState());
            result.getJSONArray("data").add(jItem);
        }
        return result;
    }

    @Override
    public BaseResponse getReviewResult(Long id) {
        ReviewRecordDAO record = reviewRecordDAOMapper.selectByPrimaryKey(id);
        if (record == null) {
            return new BaseResponse(-1, "审核记录不存在");
        }

        BookDAO book = bookDAOMapper.selectByPrimaryKey(record.getBookId());
        JSONObject result = new JSONObject();
        result.put("story", book.getTitle());
        result.put("message", record.getMessage());
        result.put("attachments", record.getAttachments());
        result.put("chapterInfo", new JSONArray());

        List<ChapterDAO> chapterList = this.getChapterList(record.getBookId(), record.getChapterIndexList());
        for (ChapterDAO chapter : chapterList) {
            JSONObject item = new JSONObject();
            item.put("index", chapter.getIndex());
            item.put("title", chapter.getTitle());
            item.put("content", chapter.getContent());
            item.put("ifLastChapter", chapter.getIfLastChapter());
            item.put("fee", chapter.getFee());
            result.getJSONArray("chapterInfo").add(item);
        }
        return new BaseResponse(result);
    }

    @Override
    public BaseResponse updateReviewResult(HttpServletRequest request) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Long id = Long.valueOf(multipartRequest.getParameter("id"));
        String result = multipartRequest.getParameter("result");
        String message = multipartRequest.getParameter("message");
        List<MultipartFile> fileList = multipartRequest.getFiles("attachments");

        UserInfo uInfo = userInfoService.getCurUserInfo();
        ReviewRecordDAO record = reviewRecordDAOMapper.selectByPrimaryKey(id);
        if (record == null) {
            return new BaseResponse(-1, "审核记录不存在");
        }

        String reviewPath = String.format("review");
        File resourceDir = new File(DATA_PATH + reviewPath);
        if (!resourceDir.exists()) {
            resourceDir.mkdirs();
        }

        JSONArray recordPath = new JSONArray();
        for (MultipartFile file : fileList) {
            try {
                String originalName = file.getOriginalFilename();
                String suffix = originalName.substring(originalName.lastIndexOf("."));
                String newName = EncodeUtil.md5Encode(UUID.randomUUID().toString()) + suffix;
                String saveName = String.format("%s/%s", reviewPath, newName);

                AliYunOSSUtil.uploadLocateFile(file, saveName);

                File newFile = new File(DATA_PATH + saveName);
                file.transferTo(newFile);

                recordPath.add(saveName);
            } catch (Exception e) {
                e.printStackTrace();
                String originalName = file.getOriginalFilename();
                return new BaseResponse(-1, "文件上传失败: " + originalName);
            }
        }

        BookDAO book = bookDAOMapper.selectByPrimaryKey(record.getBookId());
        if (StringUtils.isEmpty(record.getChapterIndexList())) {
            if (result.equals("Approved")) {
                book.setPublishState(BookPublishStateEnum.UPCOMING.getStateStr());
            }
        } else {
            List<ChapterDAO> chapterList = this.getChapterList(record.getBookId(), record.getChapterIndexList());
            for (ChapterDAO chapter : chapterList) {
                chapter.setReviewState(result);
                chapterDAOMapper.updateByPrimaryKeySelective(chapter);
                if (chapter.getIfLastChapter() != null && chapter.getIfLastChapter() && result.equals("Approved")) {
                    book.setEditState("Completed");
                }
                if (chapter.getIndex() == 1 && result.equals("Approved")) {
                    book.setPublishState("Ongoing");
                }
            }
        }


        book.setReviewState(result);
        bookDAOMapper.updateByPrimaryKeySelective(book);

        record.setReviewState(result);
        record.setResult(result);
        record.setMessage(message);
        record.setAttachments(recordPath.toString());
        record.setReviewer(uInfo.getUsername());
        record.setReviewAt(new Date());
        reviewRecordDAOMapper.updateByPrimaryKeySelective(record);
        return new BaseResponse();
    }

    @Override
    public BaseResponse publishList(ReviewQueryDTO param) {
        int total = bookDAOMapper.publishTotal(param);
        List<BookDAO> list = bookDAOMapper.publishList(param);
        BaseResponse result = new BaseResponse(new JSONArray(), total);
        for (BookDAO item : list) {
            JSONObject jItem = new JSONObject();
            jItem.put("bookId", item.getId());
            jItem.put("title", item.getTitle());
            jItem.put("author", bookDAOMapper.getAuthorName(item.getId()));
            jItem.put("publishState", item.getPublishState());
            jItem.put("publishUpdateAt", item.getPublishUpdateAt());
            jItem.put("updatedAt", item.getUpdatedAt());
            jItem.put("approvedNum", chapterDAOMapper.getReviewStateNum(item.getId(), "Approved"));
            jItem.put("releasedNum", chapterDAOMapper.getReviewStateNum(item.getId(), "Published"));
            result.getJSONArray("data").add(jItem);
        }
        return result;
    }

    @Override
    public BaseResponse getPublishResult(Long bookId) {
        BookDAO book = bookDAOMapper.selectByPrimaryKey(bookId);
        JSONObject result = new JSONObject();
        result.put("story", book.getTitle());
        result.put("status", book.getPublishState());
        result.put("firshPublishAt", book.getFirshPublishAt());
        result.put("publishUpdateAt", book.getPublishUpdateAt());
        result.put("chapterInfo", new JSONArray());
        List<ChapterDAO> chapterList = chapterDAOMapper.listByReviewState(bookId, "('Approved', 'Published')", null, null);
        for (ChapterDAO chapter : chapterList) {
            JSONObject chapterInfo = new JSONObject();
            chapterInfo.put("index", chapter.getIndex());
            chapterInfo.put("content", chapter.getContent());
            result.getJSONArray("chapterInfo").add(chapterInfo);
        }
        return new BaseResponse(result);
    }

    @Override
    public BaseResponse updatePublishResult(PublishResultDTO param) {
        BookDAO book = new BookDAO();
        book.setId(param.getBookId());
        book.setPublishUpdateAt(param.getPublishUpdateAt());
        bookDAOMapper.updateByPrimaryKeySelective(book);
        return new BaseResponse();
    }

    @Override
    public BaseResponse reviewBookSummary(Long bookId) {
        JSONObject result = new JSONObject();
        BookDAO book = bookDAOMapper.selectByPrimaryKey(bookId);
        result.put("bookId", bookId);
        result.put("title", book.getTitle());
        result.put("cover", book.getCover());
        result.put("coverWithWords", book.getCoverWithWords());
        result.put("comments", book.getComments());
        result.put("labels", book.getLabels());
        result.put("author", bookDAOMapper.getAuthorName(bookId));
        result.put("chaptersNum", chapterDAOMapper.totalChapters(bookId));
        result.put("freeChapters", chapterDAOMapper.freeChapters(bookId));
        result.put("editState", book.getEditState());
        result.put("publishState", book.getPublishState());
        result.put("firshPublishAt", book.getFirshPublishAt());
        result.put("publishUpdateAt", book.getPublishUpdateAt());
        result.put("approvedNum", chapterDAOMapper.getReviewStateNum(bookId, "Approved"));
        result.put("releasedNum", chapterDAOMapper.getReviewStateNum(bookId, "Published"));
        result.put("totalWords", chapterDAOMapper.totalWords(bookId));
        result.put("totalPrice", chapterDAOMapper.totalPrice(bookId));
        result.put("discountRate", book.getDiscountRate());
        result.put("discountStartAt", book.getDiscountStartAt());
        result.put("discountEndAt", book.getDiscountEndAt());
        return new BaseResponse(result);
    }

    @Override
    public BaseResponse getReviewChapterList(Long bookId) {
        BookDAO book = bookDAOMapper.selectByPrimaryKey(bookId);
        JSONObject result = new JSONObject();
        result.put("publishUpdateAt", book.getPublishUpdateAt());
        result.put("chapterInfo", new JSONArray());

        List<ChapterDAO> chapterList = chapterDAOMapper.listByReviewState(bookId, null, null, null);
        for (ChapterDAO chapter : chapterList) {
            JSONObject item = new JSONObject();
            item.put("id", chapter.getId());
            item.put("index", chapter.getIndex());
            item.put("wordsNum", chapter.getWordsNum());
            item.put("title", chapter.getTitle());
            item.put("content", chapter.getContent());
            item.put("reviewState", chapter.getReviewState());
            item.put("publishAt", chapter.getPublishAt());
            item.put("ifLastChapter", chapter.getIfLastChapter());
            item.put("fee", chapter.getFee());
            result.getJSONArray("chapterInfo").add(item);
        }
        return new BaseResponse(result);
    }

    @Override
    public BaseResponse updateReviewChapterList(JSONObject param) {
        Long bookId = param.getLong("bookId");
        JSONArray chapterInfo = param.getJSONArray("chapterInfo");

        Date firshPublishAt = null;
        List<ChapterDAO> chapterList = new ArrayList<>();
        for (int idx = 0; idx < chapterInfo.size(); ++idx) {
            Integer index = chapterInfo.getJSONObject(idx).getInteger("index");
            Date publishAt = chapterInfo.getJSONObject(idx).getDate("publishAt");
            ChapterDAO chapter = chapterDAOMapper.getChapter(bookId, index);
            if (chapter == null || !chapter.getReviewState().equals("Approved")) {
                return new BaseResponse(-1, String.format("该章节未通过审核: bookId=%s, index=%s", bookId, index));
            }

            if (index == 1) firshPublishAt = publishAt;
            chapter.setPublishAt(publishAt);
            chapterList.add(chapter);
        }

        if (firshPublishAt != null) {
            BookDAO book = new BookDAO();
            book.setId(bookId);
            book.setFirshPublishAt(firshPublishAt);
            bookDAOMapper.updateByPrimaryKeySelective(book);
        }

        for (ChapterDAO chapter : chapterList) {
            chapterDAOMapper.updateByPrimaryKeySelective(chapter);
        }
        return new BaseResponse();
    }
}
